package dkron

import (
	"errors"
	"github.com/distribworks/dkron/v3/dkron/httpx"
	"github.com/gin-gonic/gin"
	"github.com/hashicorp/go-uuid"
	"github.com/tidwall/buntdb"
	"net/http"
	"reflect"
	"strconv"
)

func (h *HTTPTransport) jobGetHandlerV2(c *gin.Context) {
	jobName := c.Query("job")

	job, err := h.agent.Store.GetJob(jobName, nil)
	if err != nil {
		h.logger.Error(err)
	}
	if job == nil {
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	renderJSON(c, http.StatusOK, httpx.NewResp(true, job))
}

func (h *HTTPTransport) jobsHandlerV2(c *gin.Context) {
	metadata := c.QueryMap("metadata")
	sort := c.DefaultQuery("_sort", "id")
	if sort == "id" {
		sort = "name"
	}
	order := c.DefaultQuery("_order", "ASC")
	q := c.Query("q")

	jobs, err := h.agent.Store.GetJobs(
		&JobOptions{
			Metadata: metadata,
			Sort:     sort,
			Order:    order,
			Query:    q,
			Status:   c.Query("status"),
			Disabled: c.Query("disabled"),
		},
	)
	if err != nil {
		h.logger.WithError(err).Error("api: Unable to get jobs, store not reachable.")
		return
	}

	startStr := c.DefaultQuery("current", "1")
	endStr := c.DefaultQuery("pageSize", "10")
	start, _ := strconv.Atoi(startStr)
	end, _ := strconv.Atoi(endStr)
	s := (start - 1) * end
	e := s + end
	var jobList []*Job
	if len(jobs) < s {
		jobList = []*Job{}
	}
	if len(jobs) < e {
		jobList = jobs[s:]
	}

	renderJSON(c, http.StatusOK, httpx.NewPageResp(true, int64(len(jobs)), jobList))
}

func (h *HTTPTransport) jobRunHandlerV2(c *gin.Context) {
	var jobParam Job
	err := c.ShouldBindJSON(&jobParam)
	if err != nil {
		c.AbortWithError(http.StatusBadRequest, errors.New("参数错误"))
		return
	}
	if jobParam.Name == "" {
		c.AbortWithError(http.StatusBadRequest, errors.New("参数错误"))
		return
	}

	// Call gRPC RunJob
	job, err := h.agent.GRPCClient.RunJob(jobParam.Name)
	if err != nil {
		c.AbortWithError(http.StatusNotFound, err)
		return
	}

	c.Header("Location", c.Request.RequestURI)
	c.Status(http.StatusAccepted)
	renderJSON(c, http.StatusOK, job)
}

// 执行器
func (h *HTTPTransport) executionsHandlerV2(c *gin.Context) {
	jobName := c.Query("job")

	sort := c.DefaultQuery("_sort", "")
	if sort == "id" {
		sort = "started_at"
	}
	order := c.DefaultQuery("_order", "DESC")

	job, err := h.agent.Store.GetJob(jobName, nil)
	if err != nil {
		c.AbortWithError(http.StatusNotFound, err)
		return
	}

	executions, err := h.agent.Store.GetExecutions(job.Name,
		&ExecutionOptions{
			Sort:     sort,
			Order:    order,
			Timezone: job.GetTimeLocation(),
		},
	)
	if err == buntdb.ErrNotFound {
		executions = make([]*Execution, 0)
	} else if err != nil {
		h.logger.Error(err)
		return
	}
	executionList := Page(c, reflect.TypeOf(executions), reflect.ValueOf(executions))
	renderJSON(c, http.StatusOK, httpx.NewPageResp(true, int64(len(executions)), executionList.Interface().([]*Execution)))
}

func Page(c *gin.Context, tp reflect.Type, executions reflect.Value) reflect.Value {
	startStr := c.DefaultQuery("current", "1")
	endStr := c.DefaultQuery("pageSize", "10")
	start, _ := strconv.Atoi(startStr)
	end, _ := strconv.Atoi(endStr)
	s := (start - 1) * end
	e := s + end
	if tp.Kind() == reflect.Slice {
		length := executions.Len()
		if length < s {
			executions = reflect.Value{}
		}
		if length < e {
			executions = executions.Slice(s, length)
		}
	}

	return executions
}

func (h *HTTPTransport) membersHandlerV2(c *gin.Context) {
	mems := []*MId{}
	for _, m := range h.agent.serf.Members() {
		id, _ := uuid.GenerateUUID()
		mid := &MId{m, id, m.Status.String()}
		mems = append(mems, mid)
	}
	memsList := Page(c, reflect.TypeOf(mems), reflect.ValueOf(mems))

	renderJSON(c, http.StatusOK, httpx.NewPageResp(true, int64(len(mems)), memsList.Interface().([]*MId)))

}
